package team.zero.lemon.module.workflow.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import team.zero.lemon.common.exception.CustomException;
import team.zero.lemon.common.persistence.Page;
import team.zero.lemon.common.service.CrudService;
import team.zero.lemon.module.workflow.dao.*;
import team.zero.lemon.module.workflow.entity.*;
import team.zero.lemon.module.workflow.entity.Enum.PublishType;

import java.util.Comparator;
import java.util.List;
import java.util.stream.Stream;

/**
 * Created by bolin on 2016/10/19.
 */
@Service
public class TemplateService extends CrudService<ITemplateDao, Template> {

    @Autowired
    private IActivityDao iActivityDao;
    @Autowired
    private IRuleDao iRuleDao;
    @Autowired
    private IActivityParticipantDao iActivityParticipantDao;

    @Autowired
    private IActivityFormDao iActivityFormDao;

    @Autowired
    private IFormDao iFormDao;


    @Transactional
    public boolean publish(Template template) {
        try {
            int id = 0;
            switch (PublishType.values()[template.getPublisType()]) {
                case release: {
                    template.setInsert(true);
                    template.setId(null);
                    id = save(template);
                    template.setVersionId(id);
                    template.setInsert(false);
                    save(template);
                    break;
                }
                case modify: {
                    template.setInsert(false);
                    id = template.getId();
                    save(template);
                    break;
                }
                case version: {
                    template.setInsert(true);

                    List<Template> templates = dao.findByVersionId(template.getId());
                    if (templates.size() > 0) {
                        template.setVersionId(templates.get(0).getVersionId());
                        template.setVersionNum(templates.stream().max(Comparator.comparing(a -> a.getVersionNum())).get().getVersionNum() + 1);
                    }
                    id = save(template);
                    break;
                }
            }
            int templateId = id;
            List<Activity> activities = template.getActivities();
            List<Rule> rules = template.getRules();
            List<Activity> dbactivities = iActivityDao.findByTemplateId(templateId);
            iRuleDao.deleteByTemplateId(templateId);

            activities.forEach((activity) -> {
                activity.setTemplateId(templateId);

                Stream<Activity> dbactivitie = dbactivities.stream().filter(a -> a.getId().equals(activity.getId()));
                int activityId;
                if (dbactivitie.count() == 0) {
                    activity.setInsert(true);
                    activityId = saveWfActivity(activity);
                } else {
                    activity.setInsert(false);
                    saveWfActivity(activity);
                    activityId = activity.getId();
                    iActivityParticipantDao.deleteByActivityId(activityId);
                }
                List<ActivityParticipant> activityParticipants = activity.getActivityParticipants();
                if (activityParticipants != null) {
                    activityParticipants.forEach(wfActivityParticipant -> {
                        wfActivityParticipant.setActivityId(activityId);
                        wfActivityParticipant.setInsert(true);
                        saveWfActivityParticipant(wfActivityParticipant);
                    });
                }
                rules.forEach((rule) -> {
                    if (activity.getGuid().equals(rule.getFromGuid())) {
                        rule.setFromActivityId(activityId);
                    }
                    if (activity.getGuid().equals(rule.getToGuid())) {
                        rule.setToActivityId(activityId);
                    }
                });
            });
            dbactivities.forEach((dbactivity) -> {
                Stream<Activity> activitie = activities.stream().filter(a -> a.getId().equals(dbactivity.getId()));
                if (activitie.count() == 0) {
                    iActivityDao.delete(dbactivity.getId());
                }
            });
            rules.forEach(rule -> {
                rule.setTemplateId(templateId);
                rule.setInsert(true);
                saveWfRule(rule);
            });
            return true;
        } catch (Exception e) {
            throw new CustomException(e.getMessage());
        }
    }

    public Template findTemplateById(int templateId) {
        try {

            Template template = dao.findById(templateId);
            if (template == null) {
                throw new CustomException("未找到对应的模板");
            } else {
                template.setActivities(iActivityDao.findByTemplateId(templateId));
                template.getActivities().forEach(wfActivity -> {
                    wfActivity.setActivityParticipants(iActivityParticipantDao.findByActivityId(wfActivity.getId()));
                    wfActivity.setActivityForms(iActivityFormDao.findByActivityId(wfActivity.getId()));
                    for (ActivityForm activityForm : wfActivity.getActivityForms()) {
                        Form form = iFormDao.findById(activityForm.getFormId());
                        form.setSubform(iFormDao.findFormbyParent(form.getId()));
                        activityForm.setForm(form);
                    }
                });
                template.setRules(iRuleDao.findByTemplateId(templateId));
            }
            return template;
        } catch (Exception e) {
            throw new CustomException(e.getMessage());
        }
    }


    private int saveWfActivity(Activity entity) {
        if (entity.isInsert()) {
            entity.preInsert();
            if (iActivityDao.insert(entity) > 0) {
                return entity.getId();
            } else {
                return 0;
            }
        } else {
            entity.preUpdate();
            return iActivityDao.update(entity);
        }
    }

    private int saveWfRule(Rule entity) {
        if (entity.isInsert()) {
            entity.preInsert();
            if (iRuleDao.insert(entity) > 0) {
                return entity.getId();
            } else {
                return 0;
            }
        } else {
            entity.preUpdate();
            return iRuleDao.update(entity);
        }
    }

    private int saveWfActivityParticipant(ActivityParticipant entity) {

        if (entity.isInsert()) {
            entity.preInsert();
            if (iActivityParticipantDao.insert(entity) > 0) {
                return entity.getId();
            } else {
                return 0;
            }
        } else {
            entity.preUpdate();
            return iActivityParticipantDao.update(entity);
        }
    }

    public List<Template> findAllVersionTemplate() {
        try {
            return dao.findAllVersionTemplate();
        } catch (Exception e) {
            throw new CustomException(e);
        }
    }

    public Page<Template> findVersionTemplatePage(Template template) {
        try {
            template.page.setList(dao.findVersionTemplatePage(template));
            return template.page;
        } catch (Exception e) {
            throw new CustomException(e);
        }
    }

    public List<Template> findAllTemplate() {
        return dao.findAll();
    }

}

